package com.github.live.activity;

import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.github.live.R;
import com.github.live.base.BaseActivity;
import com.github.live.base.BookingManager;
import com.github.live.manager.ChannelsManager;
import com.github.live.component.ErrorRetry;
import com.github.live.base.VisibleComponent;
import com.github.live.component.ChannelSelectorView;
import com.github.live.component.LiveSettingView;
import com.github.live.component.ReplayEpgView;
import com.github.live.manager.LiveInitializer;
import com.github.live.receiver.CloseableReceiver;
import com.github.live.util.LiveDialog;
import com.github.livebase.bean.EpgInformation;
import com.github.livebase.bean.Channel;
import com.github.live.component.ChannelInfoView;
import com.github.live.component.LiveMenuView;
import com.github.live.manager.SettingManager;
import com.github.live.receiver.ClockReceiver;
import com.github.live.util.store.HawkConfig;
import com.github.livebase.event.Event;
import com.github.livebase.event.EventBus;
import com.github.livebase.event.EventListener;
import com.github.livebase.event.SimpleEventBus;
import com.github.live.util.LogFactory;
import com.github.livebase.util.base.CollectionsUtil;
import com.github.livebase.util.base.DateUtil;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import xyz.doikki.videoplayer.player.LiveVideoView;
import xyz.doikki.videoplayer.player.VideoView;

/**
 * @author pj567
 * @date :2021/1/12
 * @description:
 */

/**
 * overwrite biao532
 * @date :2023/11/23
 * @description: 播放activity
 */
public class LivePlayActivity extends BaseActivity implements EventListener, ChannelsManager.ChangeEvent, LiveSettingView.SettingListener {
    // 播放器组件
    private LiveVideoView mVideoView;
    // 菜单组件
    private LiveMenuView menuView;
    // 设置组件
    private LiveSettingView settingView;
    private final Handler mHandler = new Handler();
    // 频道管理器
    private ChannelsManager channelsManager;
    // 时间显示组件
    private TextView tvTime;
    // 网速显示组件
    private TextView tvNetSpeed;
    // 回看状态显示组件
    private TextView replayFlags;
    // 频道详情组件
    private ChannelInfoView channelInfoView;
    // 频道号输入组件
    private ChannelSelectorView channelSelectorView;
    // 回看组件
    private ReplayEpgView epgView;
    // 超时重试控制
    private ErrorRetry retry;
    // 预约提示框
    private LiveDialog dialog;
    private SettingManager settingManager;
    private List<CloseableReceiver> receivers = new ArrayList<>(2);
    private WeakReference<LivePlayActivity> _this = new WeakReference<>(this);
    private boolean mIsDragging = false;

    @Override
    protected int getLayoutResID() {
        return R.layout.activity_live_play;
    }

    @Override
    protected void beforeCreate() {
        LiveInitializer.getInitializer().init();
    }

    @Override
    protected void init() {
        hideSysBar();
        LiveInitializer initializer = LiveInitializer.getInitializer();
        settingManager = initializer.getSettingManager();
        channelsManager = initializer.getChannelsManager();
        mVideoView = findViewById(R.id.mVideoView);
        initVideoView();
        channelInfoView = findViewById(R.id.tvBottomLayout);
        // Left Layout
        menuView = findViewById(R.id.tvLeftChannelListLayout);
        // Right Layout
        settingView = findViewById(R.id.tvRightSettingLayout);
        channelSelectorView = findViewById(R.id.selector);
        // Not in Used
        tvTime = findViewById(R.id.tvTime);
        tvNetSpeed = findViewById(R.id.tvNetSpeed);
        replayFlags = findViewById(R.id.replay_flags);
        epgView = findViewById(R.id.replay_epg_view);
        menuView.setHandler(mHandler);
        settingView.setHandler(mHandler);
        channelInfoView.setHandler(mHandler);

        // Activity中存在tvTime的强引用，当Activity被回收时，tvTime才可能被回收, 使用弱引用保证tvTime被正常回收
        SimpleEventBus.getDefault().register(EventBus.EVENT_CHANGE_TIME, this, false);
        // Initialization

        // 初始化失败
        if (!initLiveChannelList()) {
            return;
        }

        // takagen99 : Add SeekBar for VOD
        channelInfoView.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (!fromUser) {
                    return;
                }
                mHandler.removeCallbacks(updateProgress);
                mHandler.removeCallbacks(progressDragUpdate);
                channelInfoView.show();

                mHandler.postDelayed(progressDragUpdate, 2000);
                mHandler.postDelayed(updateProgress, 2000);
                channelInfoView.hide(initializer.getConfig().getChannelInfoWaitfor());
                long duration = mVideoView.getDuration();
                long newPosition = (duration * progress) / seekBar.getMax();
                channelInfoView.updateCurrentProgress((int) newPosition);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                //mIsDragging = true;
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });
        // 频道事件监听
        channelsManager.addChangeEvent(this);
        settingView.setListener(this);

        startPlay();

        // 注册广播接收器
        registerCloseableReceiver(ClockReceiver.action, new ClockReceiver());
    }


    private void startPlay() {
        Channel channel = channelsManager.getCurrentChannel();
        if (channel == null) {
            channel = channelsManager.getChannelByGroupIndexAndChannelIndex(0, 0);
        }

        Channel.Source source = channelsManager.getCurrentSource();
        // reset 会重置 player 和 renderView
        if (source == null) {
            source = channel.getSources().get(0);
        }
        settingManager.resetRenderFactory(settingManager.getRenderNameIndex(source));
        settingManager.resetScale(settingManager.getScaleNameIndex(source));
        settingManager.resetPlayer(settingManager.getPlayerNameIndex(source), source.getLive());

        epgView.setCurrentChannel(channel);
        settingView.setChannel(channel);
        channelInfoView.setSourceInfo(channelsManager.getCurrentSourceIndex(), channel.getSources().size());
        channelInfoView.setCurrentChannel(channel);
        showChannelInfo();
    }

    @Override
    public void onBackPressed() {
        if (isListOrSettingLayoutVisible()) {
            showOrHideComponent(null);
            return;
        }
        exit();
    }

    private long mExitTime = 0;
    private void exit() {
        LiveDialog dialog = getDialog();
        dialog.setTitle(R.string.tips_title);
        dialog.setHTMLMessage(getString(channelsManager.isLive()?R.string.hm_exit_live: R.string.exit_replay));
        dialog.setPositiveButton(getString(R.string.yes_confirm), (d , button)-> {
            if (!channelsManager.isLive()) {
                channelsManager.replayOver();
                return;
            }
            d.dismiss();
            finish();
        });
        dialog.showAndFocusButton(DialogInterface.BUTTON_NEGATIVE);
        mHandler.postDelayed(()-> {
            if (dialog.isShowing()) {
                dialog.dismiss();
            }
        }, 10_000);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            return super.dispatchKeyEvent(event);
        }

        int keyCode = event.getKeyCode();
        if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_Q) {
            showOrHideComponent(settingView);
            return false;//super.dispatchKeyEvent(event);
        }
        if (keyCode == KeyEvent.KEYCODE_W) {
            showOrHideComponent(epgView);
            return false;//super.dispatchKeyEvent(event);
        }
        if (isListOrSettingLayoutVisible()) {
            return super.dispatchKeyEvent(event);
        }
        if (!channelsManager.isLive() && channelInfoView.dispatchKeyEvent(event)) {
            showChannelInfo();
            return false;
        }
        // channelSelectorView 不会获取焦点， 使用dispatch触发事件
        if (channelSelectorView.dispatch(keyCode, event)) {
            return false;
        }

        switch (keyCode) {
            case KeyEvent.KEYCODE_DPAD_UP:
                if (settingManager.getSettingAttr(HawkConfig.LIVE_CHANNEL_REVERSE, false)) {
                    channelsManager.nextChannel();
                }
                else {
                    channelsManager.preChannel();
                }

                break;
            case KeyEvent.KEYCODE_DPAD_DOWN:
                if (settingManager.getSettingAttr(HawkConfig.LIVE_CHANNEL_REVERSE, false)) {
                    channelsManager.preChannel();
                }
                else {
                    channelsManager.nextChannel();
                }
                break;
            case KeyEvent.KEYCODE_DPAD_LEFT:
                channelsManager.backChannel();
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                showChannelInfo();
                break;
            case KeyEvent.KEYCODE_DPAD_CENTER:
            case KeyEvent.KEYCODE_ENTER:
            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                showOrHideComponent(menuView);
                break;
        }
        return super.dispatchKeyEvent(event);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mVideoView != null) {
            mVideoView.resume();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mVideoView == null) {
            return;
        }
       else {
            // Pause playback
            mVideoView.pause();
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterCloseableReceivers();
        SimpleEventBus.getDefault().unregister(EventBus.EVENT_CHANGE_TIME, this);
        channelsManager.removeChangeEvent(this);
        mHandler.removeCallbacks(mUpdateNetSpeedRun);
        settingView.setListener(null);
        settingManager.attach(null);
        if (mVideoView == null) {
            return;
        }
        mVideoView.release();
        mVideoView = null;
    }
    private void showChannelInfo() {
        if (!channelInfoView.isShowing()) {
            if (!channelsManager.isLive()) {
                mHandler.post(updateProgress);
            }
        }
        channelInfoView.show();
        channelInfoView.hide(LiveInitializer.getInitializer()
                .getConfig()
                .getChannelInfoWaitfor());
    }

    private void showOrHideComponent(VisibleComponent component) {
        if (component != settingView && settingView.isShowing()) {
            settingView.hide();
        }
        if (component != channelInfoView && channelInfoView.isShowing()) {
            channelInfoView.hide();
        }
        if (component != epgView && epgView.isShowing()) {
            epgView.hide();
        }
        if (component != menuView && menuView.isShowing()) {
            menuView.hide();
        }
        if (component == null) {
            return;
        }
        if (component.isShowing()) {
            component.hide();
        }
        else {
            component.show();
        }
    }

    private void initVideoView() {
        settingManager.attach(mVideoView);
        this.retry = new ErrorRetry(mHandler, this, mVideoView);
        mVideoView.setStateChangeListener(this.retry);
        mVideoView.addStateChangeListener(new LiveVideoView.StateChangeListener(){
            @Override
            public void onPlayStateChanged(int playState) {
               if (playState == VideoView.STATE_PREPARED) {
                    if (mVideoView.getVideoSize().length >= 2) {
                        channelInfoView.setSize(mVideoView.getVideoSize()[0], mVideoView.getVideoSize()[1]);
                    }
                    // Show SeekBar if it's a VOD (with duration)
                    int duration = (int) mVideoView.getDuration();
                    if (!channelsManager.isLive()){
                        channelInfoView.showProgress(duration);
                    } else {
                        channelInfoView.hideProgress();
                    }
                }
            }
        });
    }

    private Runnable progressDragUpdate = () -> {
        LivePlayActivity __this = _this.get();
        if (__this == null) {
            return;
        }
        long duration = mVideoView.getDuration();
        long newPosition = __this.channelInfoView.computeProgress(duration);
        __this.mVideoView.seekTo((int) newPosition);
        __this.showChannelInfo();
        // 58545.5265489
    };
    private Runnable updateProgress = new Runnable() {
        @Override
        public void run() {
            LivePlayActivity __this = _this.get();
            if (__this == null) {
                return;
            }
            //if (!__this.mIsDragging) {
                __this.channelInfoView.updateCurrentProgress((int) __this.mVideoView.getCurrentPosition());
            //}
            if (__this.channelsManager.isLive() || __this.channelInfoView.getVisibility() != View.VISIBLE) {
                __this.mHandler.removeCallbacks(this);
                return;
            }
            __this.mHandler.removeCallbacks(this);
            __this.mHandler.postDelayed(this, 1000);

        }
    };

    private boolean initLiveChannelList() {
        if (channelsManager.isEmptyChannels()) {
            Toast.makeText(this, R.string.channel_empty, Toast.LENGTH_SHORT).show();
            finish();
            return false;
        }

        Intent intent = getIntent();
        if (intent != null && intent.getExtras() != null) {
            int number = intent.getIntExtra("number", -1);
            if(number != -1) {
                channelsManager.setActiveByNumber(number);
            }
        }
        showTime();
        showNetSpeed();

        menuView.setVisibility(View.INVISIBLE);
        settingView.setVisibility(View.INVISIBLE);
        return true;
    }

   /* @Subscribe(threadMode = ThreadMode.MAIN)
    public void refresh(RefreshEvent event) {
        if (event.type == RefreshEvent.TYPE_LIVEPLAY_UPDATE) {
            Bundle bundle = (Bundle) event.obj;
            int channelGroupIndex = bundle.getInt("groupIndex", 0);
            int liveChannelIndex = bundle.getInt("channelIndex", 0);
            channelsManager.setChannelByGroupIndexChannelIndex(channelGroupIndex, liveChannelIndex);
        }
    }*/

    private boolean isListOrSettingLayoutVisible() {
        return menuView.isShowing()
                || settingView.isShowing()
                || epgView.isShowing();
    }

    private void showTime() {
        if (settingManager.getSettingAttr(HawkConfig.LIVE_SHOW_TIME, false)) {
            Date date = Calendar.getInstance().getTime();
            tvTime.setText(DateUtil.format(DateUtil.HH_mm, date));
            tvTime.setVisibility(View.VISIBLE);
            return;
        }
        tvTime.setVisibility(View.GONE);
    }

    private void showNetSpeed() {
        if (settingManager.getSettingAttr(HawkConfig.LIVE_SHOW_NET_SPEED, false)) {
            mHandler.post(mUpdateNetSpeedRun);
            tvNetSpeed.setVisibility(View.VISIBLE);
            return;
        }
        mHandler.removeCallbacks(mUpdateNetSpeedRun);
        tvNetSpeed.setVisibility(View.GONE);
    }

    private void registerCloseableReceiver(String action, CloseableReceiver receiver) {
        IntentFilter filter = new IntentFilter();
        filter.addAction(action);
        registerReceiver(receiver, filter);
        receivers.add(receiver);
    }
    private void unregisterCloseableReceivers() {
        CollectionsUtil.foreach(receivers, (r) -> {
            unregisterReceiver(r);
            r.close();
        });
        receivers.clear();
    }
    private Runnable mUpdateNetSpeedRun = new Runnable() {
        @Override
        public void run() {
            LivePlayActivity __this = _this.get();
            if (__this == null) {
                return;
            }
            if (__this.mVideoView == null) return;
            __this.tvNetSpeed.setText(String.format("%.2fMB/s", (float) __this.mVideoView.getTcpSpeed() / 1024.0 / 1024.0));
            __this.mHandler.postDelayed(this, 2000);
        }
    };

    private LiveDialog getDialog() {
        if (dialog == null) {
            dialog = new LiveDialog(this, false, null);
            dialog.setNegativeButton(getText(R.string.cancel), (dialog, which) -> {
                dialog.dismiss();
            });
        }
        if (dialog.isShowing()) {
            dialog.dismiss();
        }
        return dialog;
    }
    /**
     * 弹出预约提醒
     * @param information
     */
    private void showBooking(EpgInformation information) {
        LiveDialog dialog = getDialog();
        dialog.setTitle(R.string.booking_title);
        Channel channel = ChannelsManager.getChannelByFilter((c)-> {
            return c.getId().equals(information.getChannelId());
        });
        if (channel == null) {
            return;
        }

        dialog.setPositiveButton(getString(R.string.yes_confirm), (d, which) -> {
            channelsManager.setActiveByNumber(channel.getNumber());
            d.dismiss();
        });

        dialog.setHTMLMessage(
                getString(R.string.booking_tips, information.getTitle(), channel.getName())
        );
        dialog.showAndFocusButton(DialogInterface.BUTTON_POSITIVE);
        this.mHandler.postDelayed(()-> {
            if (dialog.isShowing()) {
                dialog.dismiss();
            }
        }, 30_000);
    }

    @Override
    public void onEvent(Event event) {
        if (!Event.isEvent(event, EventBus.EVENT_CHANGE_TIME)) {
            return;
        }
        LivePlayActivity __this = _this.get();
        if (__this == null) {
            return;
        }
        TextView time = __this.tvTime;
        Date date = event.getAttachObject();
        if (time != null) {
            time.setText(DateUtil.format(DateUtil.HH_mm, date));
        }

        BookingManager manager = BookingManager.singleton();
        EpgInformation booking = manager.select(date.getTime());
        if (booking == null) {
            return;
        }
        __this.showBooking(booking);
        manager.remove(booking);
    }

    @Override
    public void onSourceChange(Channel.Source old, Channel.Source newSource) {
        showChannelInfo();
        Channel newChannel = channelsManager.getCurrentChannel();
        channelInfoView.setSourceInfo(channelsManager.getCurrentSourceIndex(), newChannel.getSources().size());

        // reset 会重置 player 和 renderView
        SettingManager s = settingManager;
        s.resetScale(s.getScaleNameIndex(newSource));
        s.resetRenderFactory(s.getRenderNameIndex(newSource));
        String live = newSource.getLive();
        s.resetPlayer(s.getPlayerNameIndex(newSource), live);
        LogFactory.debug(LivePlayActivity.class, "source change live url is {}", live);
    }

    @Override
    public void onLiveChange(Channel.Source source, EpgInformation information, boolean isLive) {
        replayFlags.setVisibility(isLive?View.GONE:View.VISIBLE);
        if (isLive) {
            channelInfoView.setCurrentChannel(channelsManager.getCurrentChannel());
            channelInfoView.hideProgress();
            this.onSourceChange(source, source);
        }
        else {
            channelInfoView.showProgress(information.getDuration());
            channelInfoView.updateEpgInformation(information, null);
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            source.put("playseek", DateUtil.format(format, new Date(information.getStart())) + "-" +
                    DateUtil.format(format, new Date(information.getEnd())) );
            String replayUrl = source.getReplay();
            mVideoView.setUrl(replayUrl);
            LogFactory.debug(LivePlayActivity.class, "url with playseek={}", replayUrl);
            source.remove("playseek");
            mVideoView.replay(true);
            showChannelInfo();
        }
    }

    @Override
    public void onNoChange() {
        showChannelInfo();
    }

    @Override
    public void onChannelChange(Channel old, Channel newChannel) {
        showOrHideComponent(null);
        epgView.setCurrentChannel(newChannel);
        channelInfoView.setCurrentChannel(newChannel);
        // 设置源
        settingView.setChannel(newChannel);
        if (retry != null) {
            retry.reset();
        }
    }

    @Override
    public void onSourceChange(int sourceIndex) {

    }

    @Override
    public void onScaleChange(int index) {

    }

    @Override
    public void onPlayerChange(int index) {

    }

    @Override
    public void onTimeShowChange() {
        showTime();
    }

    @Override
    public void onNetSpeedShowChange() {
        showNetSpeed();
    }
}